home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / help.cc < prev    next >
C/C++ Source or Header  |  1997-08-14  |  23KB  |  1,104 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. /* Modified by Klaus Gebhardt, 1996 */
  24.  
  25. #ifdef HAVE_CONFIG_H
  26. #include <config.h>
  27. #endif
  28.  
  29. #include <csignal>
  30. #include <cstdlib>
  31. #include <cstring>
  32.  
  33. #include <string>
  34.  
  35. #include <iostream.h>
  36. #include <fstream.h>
  37. #include <strstream.h>
  38.  
  39. #ifdef HAVE_UNISTD_H
  40. #ifdef HAVE_SYS_TYPES_H
  41. #include <sys/types.h>
  42. #endif
  43. #include <unistd.h>
  44. #endif
  45.  
  46. #include "str-vec.h"
  47.  
  48. #include <defaults.h>
  49. #include "defun.h"
  50. #include "dirfns.h"
  51. #include "error.h"
  52. #include "fn-cache.h"
  53. #include "gripes.h"
  54. #include "help.h"
  55. #include "input.h"
  56. #include "oct-obj.h"
  57. #include "pager.h"
  58. #include "pathsearch.h"
  59. #include "pt-const.h"
  60. #include "pt-exp.h"
  61. #include "pt-pr-code.h"
  62. #include "sighandlers.h"
  63. #include "symtab.h"
  64. #include "syswait.h"
  65. #include "toplev.h"
  66. #include "unwind-prot.h"
  67. #include "utils.h"
  68. #include "variables.h"
  69.  
  70. #if defined (__EMX__)
  71. extern "C"
  72. {
  73. #include "info/info.h"
  74. #include "info/dribble.h"
  75. #include "info/terminal.h"
  76.  
  77.   extern int external_info_search ();
  78.   extern int index_entry_exists ();
  79.   extern int do_info_index_search ();
  80.   extern void finish_info_session ();
  81.   extern char *replace_in_documentation ();
  82. }
  83. #endif
  84.  
  85. // Name of the info file specified on command line.
  86. // (--info-file file)
  87. string Vinfo_file;
  88.  
  89. // Name of the info reader we'd like to use.
  90. // (--info-program program)
  91. string Vinfo_prog;
  92.  
  93. // If TRUE, don't print additional help message in help and usage
  94. // functions.
  95. static bool Vsuppress_verbose_help_message;
  96.  
  97. static help_list operators[] =
  98. {
  99.   { "!",
  100.     "Logical not operator.  See also `~'.\n", },
  101.  
  102.   { "!=",
  103.     "Logical not equals operator.  See also `~' and `<>'.\n", },
  104.  
  105.   { "\"",
  106.     "String delimiter.\n", },
  107.  
  108.   { "#",
  109.     "Begin comment character.  See also `%'.", },
  110.  
  111.   { "%",
  112.     "Begin comment charcter.  See also `#'.", },
  113.  
  114.   { "&",
  115.     "Logical and operator.  See also `&&'.", },
  116.  
  117.   { "&&",
  118.     "Logical and operator.  See also `&'.", },
  119.  
  120.   { "'",
  121.     "Matrix transpose operator.  For complex matrices, computes the\n\
  122. complex conjugate (Hermitian) transpose.  See also `.''\n\
  123. \n\
  124. The single quote character may also be used to delimit strings, but\n\
  125. it is better to use the double quote character, since that is never\n\
  126. ambiguous", },
  127.  
  128.   { "(",
  129.     "Array index or function argument delimiter.", },
  130.  
  131.   { ")",
  132.     "Array index or function argument delimiter.", },
  133.  
  134.   { "*",
  135.     "Multiplication operator.  See also `.*'", },
  136.  
  137.   { "**",
  138.     "Power operator.  See also `^', `.**', and `.^'", },
  139.  
  140.   { "+",
  141.     "Addition operator.", },
  142.  
  143.   { "++",
  144.     "Increment operator.  As in C, may be applied as a prefix or postfix operator.", },
  145.  
  146.   { ",",
  147.     "Array index, function argument, or command separator.", },
  148.  
  149.   { "-",
  150.     "Subtraction or unary negation operator.", },
  151.  
  152.   { "--",
  153.     "Decrement operator.  As in C, may be applied as a prefix or postfix operator.", },
  154.  
  155.   { ".'",
  156.     "Matrix transpose operator.  For complex matrices, computes the\n\
  157. transpose, *not* the complex conjugate transpose.  See also `''.", },
  158.  
  159.   { ".*",
  160.     "Element by element multiplication operator.  See also `*'.", },
  161.  
  162.   { ".**",
  163.     "Element by element power operator.  See also `**', `^', and `.^'.", },
  164.  
  165.   { "./",
  166.     "Element by element division operator.  See also `/' and `\\'.", },
  167.  
  168.   { ".^",
  169.     "Element by element power operator.  See also `**', `^', and `.^'.", },
  170.  
  171.   { "/",
  172.     "Right division.  See also `\\' and `./'.", },
  173.  
  174.   { ":",
  175.     "Select entire rows or columns of matrices.", },
  176.  
  177.   { ";",
  178.     "Array row or command separator.  See also `,'.", },
  179.  
  180.   { "<",
  181.     "Less than operator.", },
  182.  
  183.   { "<=",
  184.     "Less than or equals operator.", },
  185.  
  186.   { "<>",
  187.     "Logical not equals operator.  See also `!=' and `~='.", },
  188.  
  189.   { "=",
  190.     "Assignment operator.", },
  191.  
  192.   { "==",
  193.     "Equality test operator.", },
  194.  
  195.   { ">",
  196.     "Greater than operator.", },
  197.  
  198.   { ">=",
  199.     "Greater than or equals operator.", },
  200.  
  201.   { "[",
  202.     "Return list delimiter.  See also `]'.", },
  203.  
  204.   { "\\",
  205.     "Left division operator.  See also `/' and `./'.", },
  206.  
  207.   { "]",
  208.     "Return list delimiter.  See also `['.", },
  209.  
  210.   { "^",
  211.     "Power operator.  See also `**', `.^', and `.**.'", },
  212.  
  213.   { "|",
  214.     "Logical or operator.  See also `||'.", },
  215.  
  216.   { "||",
  217.     "Logical or operator.  See also `|'.", },
  218.  
  219.   { "~",
  220.     "Logical not operator.  See also `!' and `~'.", },
  221.  
  222.   { "~=",
  223.     "Logical not equals operator.  See also `<>' and `!='.", },
  224.  
  225.   { 0, 0, },
  226. };
  227.  
  228. static help_list keywords[] =
  229. {
  230.   { "all_va_args",
  231.     "Pass all unnamed arguments to another function call.", },
  232.  
  233.   { "break",
  234.     "Exit the innermost enclosing while or for loop.", },
  235.  
  236.   { "catch",
  237.     "begin the cleanup part of a try-catch block", },
  238.  
  239.   { "continue",
  240.     "Jump to the end of the innermost enclosing while or for loop.", },
  241.  
  242.   { "else",
  243.     "Alternate action for an if block.", },
  244.  
  245.   { "elseif",
  246.     "Alternate conditional test for an if block.", },
  247.  
  248.   { "end",
  249.     "Mark the end of any for, if, while, or function block.", },
  250.  
  251.   { "end_try_catch",
  252.     "Mark the end of an try-catch block.", }, 
  253.  
  254.   { "end_unwind_protect",
  255.     "Mark the end of an unwind_protect block.", }, 
  256.  
  257.   { "endfor",
  258.     "Mark the end of a for loop.", },
  259.  
  260.   { "endfunction",
  261.     "Mark the end of a function.", },
  262.  
  263.   { "endif",
  264.     "Mark the end of an if block.", },
  265.  
  266.   { "endwhile",
  267.     "Mark the end of a while loop.", },
  268.  
  269.   { "for",
  270.     "Begin a for loop.", },
  271.  
  272.   { "function",
  273.     "Begin a function body.", },
  274.  
  275.   { "global",
  276.     "Declare variables to have global scope.", },
  277.  
  278.   { "gplot",
  279.     "Produce 2-D plots using gnuplot-like command syntax.", },
  280.  
  281.   { "gsplot",
  282.     "Produce 3-D plots using gnuplot-like command syntax.", },
  283.  
  284.   { "if",
  285.     "Begin an if block.", },
  286.  
  287.   { "return",
  288.     "Return from a function.", },
  289.  
  290.   { "try",
  291.     "Begin a try-catch block.", }, 
  292.  
  293.   { "unwind_protect",
  294.     "Begin an unwind_protect block.", }, 
  295.  
  296.   { "unwind_protect_cleanup",
  297.     "Begin the cleanup section of an unwind_protect block.", }, 
  298.  
  299.   { "while",
  300.     "Begin a while loop.", },
  301.  
  302.   { 0, 0, },
  303. };
  304.  
  305. // Return a copy of the operator or keyword names.
  306.  
  307. string_vector
  308. names (help_list *lst, int& count)
  309. {
  310.   string_vector retval;
  311.  
  312.   count = 0;
  313.   help_list *ptr = lst;
  314.   while (ptr->name)
  315.     {
  316.       count++;
  317.       ptr++;
  318.     }
  319.  
  320.   if (count > 0)
  321.     {
  322.       retval.resize (count);
  323.  
  324.       ptr = lst;
  325.       for (int i = 0; i < count; i++)
  326.     {
  327.       retval[i] = ptr->name;
  328.       ptr++;
  329.     }
  330.     }
  331.  
  332.   return retval;
  333. }
  334.  
  335. help_list *
  336. operator_help (void)
  337. {
  338.   return operators;
  339. }
  340.  
  341. help_list *
  342. keyword_help (void)
  343. {
  344.   return keywords;
  345. }
  346.  
  347. #if defined (USE_GNU_INFO)
  348. static void
  349. additional_help_message (ostream& os)
  350. {
  351.   if (! Vsuppress_verbose_help_message)
  352.     os << "\n\
  353. Additional help for builtin functions, operators, and variables\n\
  354. is available in the on-line version of the manual.\n\
  355. \n\
  356. Use the command `help -i <topic>' to search the manual index.\n";
  357. }
  358. #else
  359. static void
  360. additional_help_message (ostream&)
  361. {
  362. }
  363. #endif
  364.  
  365. void
  366. print_usage (const string& nm, int just_usage)
  367. {
  368.   symbol_record *sym_rec = global_sym_tab->lookup (nm, 0, 0);
  369.   if (sym_rec)
  370.     {
  371.       string h = sym_rec->help ();
  372.  
  373.       if (h.length () > 0)
  374.     {
  375.       octave_stdout << "\n*** " << nm << ":\n\n"
  376.         << h << "\n";
  377.  
  378.       if (! just_usage)
  379.         additional_help_message (octave_stdout);
  380.     }
  381.     }
  382.   else
  383.     warning ("no usage message found for `%s'", nm.c_str ());
  384. }
  385.  
  386. static void
  387. display_names_from_help_list (ostream& os, help_list *list,
  388.                   const char *desc)
  389. {
  390.   int count = 0;
  391.   string_vector symbols = names (list, count);
  392.   if (! symbols.empty ())
  393.     {
  394.       os << "\n*** " << desc << ":\n\n";
  395.       symbols.list_in_columns (os);
  396.     }
  397. }
  398.  
  399. static string
  400. print_symbol_type (ostream& os, symbol_record *sym_rec,
  401.            const string& name, int print)
  402. {
  403.   string retval;
  404.  
  405.   if (sym_rec->is_user_function ())
  406.     {
  407.       tree_fvc *defn = sym_rec->def ();
  408.  
  409.       string fn = defn->fcn_file_name ();
  410.  
  411.       if (! fn.empty ())
  412.     {
  413.       string ff = fcn_file_in_path (fn);
  414.  
  415.       ff = ff.length () > 0 ? ff : fn;
  416.  
  417.       if (print)
  418.         os << name
  419.            << " is the function defined from:\n"
  420.            << ff << "\n";
  421.       else
  422.         retval = ff;
  423.     }
  424.       else
  425.     {
  426.       if (print)
  427.         os << name << " is a user-defined function\n";
  428.       else
  429.         retval = "user-defined function";
  430.     }
  431.     }
  432.   else if (sym_rec->is_text_function ())
  433.     {
  434.       if (print)
  435.     os << name << " is a builtin text-function\n";
  436.       else
  437.     retval = "builtin text-function";
  438.     }
  439.   else if (sym_rec->is_builtin_function ())
  440.     {
  441.       if (print)
  442.     os << name << " is a builtin function\n";
  443.       else
  444.     retval = "builtin function";
  445.     }
  446.   else if (sym_rec->is_user_variable ())
  447.     {
  448.       if (print)
  449.     os << name << " is a user-defined variable\n";
  450.       else
  451.     retval = "user-defined variable";
  452.     }
  453.   else if (sym_rec->is_builtin_variable ())
  454.     {
  455.       if (print)
  456.     os << name << " is a builtin variable\n";
  457.       else
  458.     retval = "builtin variable";
  459.     }
  460.   else
  461.     {
  462.       if (print)
  463.     os << "which: `" << name << "' has unknown type\n";
  464.       else
  465.     retval = "unknown type";
  466.     }
  467.  
  468.   return retval;
  469. }
  470.  
  471. static void
  472. display_symtab_names (ostream& os, const string_vector& names,
  473.               int /* count */, const string& desc)
  474. {
  475.   if (! names.empty ())
  476.     {
  477.       os << "\n*** " << desc << ":\n\n";
  478.       names.list_in_columns (os);
  479.     }
  480. }
  481.  
  482. static void
  483. simple_help (void)
  484. {
  485.   display_names_from_help_list (octave_stdout, operator_help (),
  486.                 "operators");
  487.  
  488.   display_names_from_help_list (octave_stdout, keyword_help (),
  489.                 "reserved words");
  490.  
  491. #ifdef LIST_SYMBOLS
  492. #undef LIST_SYMBOLS
  493. #endif
  494. #define LIST_SYMBOLS(type, msg) \
  495.   do \
  496.     { \
  497.       int count; \
  498.       string_vector names = global_sym_tab->list (count, 0, 0, 1, type); \
  499.       display_symtab_names (octave_stdout, names, count, msg); \
  500.     } \
  501.   while (0)
  502.  
  503.   // XXX FIXME XXX -- is this distinction needed?
  504.  
  505.   LIST_SYMBOLS (symbol_def::TEXT_FUNCTION,
  506.         "text functions (these names are also reserved)");
  507.  
  508.   LIST_SYMBOLS (symbol_def::MAPPER_FUNCTION, "mapper functions");
  509.  
  510.   LIST_SYMBOLS (symbol_def::BUILTIN_FUNCTION, "general functions");
  511.  
  512.   LIST_SYMBOLS (symbol_def::BUILTIN_VARIABLE, "builtin variables");
  513.  
  514.   // Also need to list variables and currently compiled functions from
  515.   // the symbol table, if there are any.
  516.  
  517.   // Also need to search octave_path for script files.
  518.  
  519.   dir_path p (Vload_path);
  520.  
  521.   string_vector dirs = p.all_directories ();
  522.  
  523.   int len = dirs.length ();
  524.  
  525.   for (int i = 0; i < len; i++)
  526.     {
  527.       string_vector names = octave_fcn_file_name_cache::list (dirs[i]);
  528.  
  529.       if (! names.empty ())
  530.     {
  531.       octave_stdout << "\n*** function files in "
  532.             << make_absolute (dirs[i], Vcurrent_directory)
  533.             << ":\n\n";
  534.  
  535.       names.list_in_columns (octave_stdout);
  536.     }
  537.     }
  538.  
  539.   additional_help_message (octave_stdout);
  540. }
  541.  
  542. #if defined (USE_GNU_INFO)
  543. static int
  544. try_info (const string& nm)
  545. {
  546.   if (Vinfo_prog.length () > 0)
  547.     {
  548.       int status = 0;
  549.  
  550.       static char *cmd_str = 0;
  551.  
  552.       delete [] cmd_str;
  553.       cmd_str = 0;
  554.  
  555.       ostrstream cmd_buf;
  556.  
  557.       cmd_buf << Vinfo_prog << " --file " << Vinfo_file;
  558.  
  559.       string directory_name = Vinfo_file;
  560.       size_t pos = directory_name.rfind ('/');
  561.  
  562.       if (pos != NPOS)
  563.     {
  564.       directory_name.resize (pos + 1);
  565.       cmd_buf << " --directory " << directory_name;
  566.     }
  567.  
  568.       if (nm.length () > 0)
  569.     cmd_buf << " --index-search " << nm;
  570.  
  571.       cmd_buf << ends;
  572.  
  573.       cmd_str = cmd_buf.str ();
  574.  
  575.       volatile octave_interrupt_handler old_interrupt_handler
  576.     = octave_ignore_interrupts ();
  577.  
  578.       status = system (cmd_str);
  579.  
  580.       octave_set_interrupt_handler (old_interrupt_handler);
  581.  
  582.       if (WIFEXITED (status))
  583.     status = WEXITSTATUS (status);
  584.       else
  585.     status = 127;
  586.  
  587.       return status;
  588.     }
  589.   else
  590.     {
  591.       volatile octave_interrupt_handler old_interrupt_handler
  592.     = octave_ignore_interrupts ();
  593.  
  594.       int status = 0;
  595.  
  596.       char *directory_name = strdup (Vinfo_file.c_str ());
  597.       char *temp = filename_non_directory (directory_name);
  598.  
  599.       if (temp != directory_name)
  600.     {
  601.       *temp = 0;
  602.       info_add_path (directory_name, INFOPATH_PREPEND);
  603.     }
  604.  
  605.       delete [] directory_name;
  606.  
  607.       NODE *initial_node = info_get_node (Vinfo_file.c_str (), 0);
  608.  
  609.       if (! initial_node)  status = 127;
  610.       else
  611.     {
  612.       status = external_info_search(initial_node, 0,
  613.                     Vinfo_file.c_str (), nm.c_str ());
  614.       if (status == 1)
  615.         {
  616.           char *format = replace_in_documentation
  617.         ("Type \"\\[quit]\" to quit, \"\\[get-help-window]\" for help.");
  618.           window_message_in_echo_area (format);
  619.  
  620.           info_read_and_dispatch ();
  621.  
  622. #ifdef __EMX__
  623.           terminal_goto_xy (0, screenheight - 2);
  624. #else
  625.           terminal_goto_xy (0, screenheight - 1);
  626. #endif
  627.           terminal_clear_to_eol ();
  628.           terminal_unprep_terminal ();
  629.         }
  630.  
  631.       status = status * status - 1;
  632.  
  633.       finish_info_session (initial_node, 0);
  634.     }
  635.  
  636.       octave_set_interrupt_handler (old_interrupt_handler);
  637.  
  638.       return status;
  639.     }
  640. }
  641.  
  642. static void
  643. help_from_info (const string_vector& argv, int idx, int argc)
  644. {
  645.   if (idx == argc)
  646.     {
  647.       int status = try_info (string ());
  648.  
  649.       if (status)
  650.     {
  651.       if (status < 0)
  652.         {
  653.           message ("help", "sorry, `%s' is not indexed in the manual",
  654.                string ().c_str ());
  655.           sleep (2);
  656.         }
  657.       else  error ("help: unable to find info!");
  658.     }
  659.     }
  660.   else
  661.     {
  662.       for (int i = idx; i < argc; i++)
  663.     {
  664.       int status = try_info (argv[i]);
  665.  
  666.       if (status)
  667.         {
  668.           if (status < 0)
  669.         {
  670.           message ("help",
  671.                "sorry, `%s' is not indexed in the manual",
  672.                argv[i].c_str ());
  673.           sleep (2);
  674.         }
  675.           else
  676.         {
  677.           error ("help: unable to find info!");
  678.           break;
  679.         }
  680.         }
  681.     }
  682.     }
  683. }
  684. #else
  685. static void
  686. help_from_info (const string_vector&, int, int)
  687. {
  688.   message (0, "sorry, help -i is not available in this version of Octave");
  689. }
  690. #endif
  691.  
  692. int
  693. help_from_list (ostream& os, const help_list *list,
  694.         const string& nm, int usage)
  695. {
  696.   char *name;
  697.   while ((name = list->name) != 0)
  698.     {
  699.       if (strcmp (name, nm.c_str ()) == 0)
  700.     {
  701.       if (usage)
  702.         os << "\nusage: ";
  703.       else
  704.         {
  705.           os << "\n*** " << nm << ":\n\n";
  706.         }
  707.  
  708.       os << list->help << "\n";
  709.  
  710.       return 1;
  711.     }
  712.       list++;
  713.     }
  714.   return 0;
  715. }
  716.  
  717. static void
  718. builtin_help (int argc, const string_vector& argv)
  719. {
  720.   help_list *op_help_list = operator_help ();
  721.   help_list *kw_help_list = keyword_help ();
  722.  
  723.   for (int i = 1; i < argc; i++)
  724.     {
  725.       if (help_from_list (octave_stdout, op_help_list, argv[i], 0))
  726.     continue;
  727.  
  728.       if (help_from_list (octave_stdout, kw_help_list, argv[i], 0))
  729.     continue;
  730.  
  731.       symbol_record *sym_rec = lookup_by_name (argv[i], 0);
  732.  
  733.       if (sym_rec && sym_rec->is_defined ())
  734.     {
  735.       string h = sym_rec->help ();
  736.  
  737.       if (h.length () > 0)
  738.         {
  739.           print_symbol_type (octave_stdout, sym_rec, argv[i], 1);
  740.           octave_stdout << "\n" << h << "\n";
  741.           continue;
  742.         }
  743.     }
  744.  
  745.       string path = fcn_file_in_path (argv[i]);
  746.  
  747.       string h = get_help_from_file (path);
  748.  
  749.       if (! h.empty ())
  750.     {
  751.       octave_stdout << argv[i] << " is the file:\n"
  752.         << path << "\n\n" << h << "\n";
  753.  
  754.       continue;
  755.     }
  756.  
  757.       octave_stdout << "\nhelp: sorry, `" << argv[i]
  758.             << "' is not documented\n"; 
  759.     }
  760.  
  761.   additional_help_message (octave_stdout);
  762. }
  763.  
  764. #if defined (USE_GNU_INFO)
  765. DEFUN_TEXT (help, args, ,
  766.   "help [-i] [topic ...]\n\
  767. \n\
  768. print cryptic yet witty messages")
  769. #else
  770. DEFUN_TEXT (help, args, ,
  771.   "help [topic ...]\n\
  772. \n\
  773. print cryptic yet witty messages")
  774. #endif
  775. {
  776.   octave_value_list retval;
  777.  
  778.   int argc = args.length () + 1;
  779.  
  780.   string_vector argv = args.make_argv ("help");
  781.  
  782.   if (error_state)
  783.     return retval;
  784.  
  785.   if (argc == 1)
  786.     {
  787.       simple_help ();
  788.     }
  789.   else
  790.     {
  791.       if (argv[1] == "-i")
  792.     {
  793.       help_from_info (argv, 2, argc);
  794.     }
  795.       else
  796.     {
  797.       builtin_help (argc, argv);
  798.     }
  799.     }
  800.  
  801.   return retval;
  802. }
  803.  
  804. DEFUN_TEXT (type, args, nargout,
  805.   "type NAME ...]\n\
  806. \n\
  807. display the definition of each NAME that refers to a function")
  808. {
  809.   octave_value_list retval;
  810.  
  811.   begin_unwind_frame ("Ftype");
  812.  
  813.   int argc = args.length () + 1;
  814.  
  815.   string_vector argv = args.make_argv ("type");
  816.  
  817.   if (error_state)
  818.     return retval;
  819.  
  820.   if (argc > 1)
  821.     {
  822.       // XXX FIXME XXX -- we should really use getopt ()
  823.  
  824.       bool quiet = false;
  825.       bool pr_orig_txt = true;
  826.  
  827.       int idx;
  828.  
  829.       for (idx = 1; idx < argc; idx++)
  830.     {
  831.       if (argv[idx] == "-q" || argv[idx] == "-quiet")
  832.         quiet = true;
  833.       else if (argv[idx] == "-t" || argv[idx] == "-transformed")
  834.         pr_orig_txt = false;
  835.       else
  836.         break;
  837.     }
  838.  
  839.       if (idx == argc)
  840.     {
  841.       print_usage ("type");
  842.       return retval;
  843.     }
  844.  
  845.       ostrstream output_buf;
  846.  
  847.       for (int i = idx; i < argc; i++)
  848.     {
  849.       string id = argv[i];
  850.       string elts;
  851.  
  852.       if (id[id.length () - 1] != '.')
  853.         {
  854.           size_t pos = id.find ('.');
  855.  
  856.           if (pos != NPOS)
  857.         {
  858.           elts = id.substr (pos+1);
  859.           id = id.substr (0, pos);
  860.         }
  861.         }
  862.  
  863.       symbol_record *sym_rec = lookup_by_name (id, 0);
  864.  
  865.       if (sym_rec)
  866.         {
  867.           if (sym_rec->is_user_function ())
  868.         {
  869.           tree_fvc *defn = sym_rec->def ();
  870.  
  871.           string fn = defn->fcn_file_name ();
  872.           string ff = fcn_file_in_path (fn);
  873.  
  874.           if (pr_orig_txt && ! ff.empty ())
  875.             {
  876.               ifstream fs (ff.c_str (), ios::in);
  877.  
  878.               if (fs)
  879.             {
  880.               if (nargout == 0 && ! quiet)
  881.                 output_buf << argv[i]
  882.                        << " is the function defined from:\n"
  883.                        << ff << "\n\n";
  884.  
  885.               char ch;
  886.  
  887.               while (fs.get (ch))
  888.                 output_buf << ch;
  889.             }
  890.               else
  891.             output_buf << "unable to open `" << ff
  892.                    << "' for reading!\n";
  893.             }
  894.           else
  895.             {
  896.               if (nargout == 0 && ! quiet)
  897.             output_buf << argv[i]
  898.                    << " is a user-defined function:\n\n";
  899.  
  900.               tree_print_code tpc (output_buf, "", pr_orig_txt);
  901.  
  902.               defn->accept (tpc);
  903.             }
  904.         }
  905.  
  906.           // XXX FIXME XXX -- this code should be shared with
  907.           // Fwhich.
  908.  
  909.           else if (sym_rec->is_text_function ())
  910.         output_buf << argv[i] << " is a builtin text-function\n";
  911.           else if (sym_rec->is_builtin_function ())
  912.         output_buf << argv[i] << " is a builtin function\n";
  913.           else if (sym_rec->is_user_variable ()
  914.                || sym_rec->is_builtin_variable ())
  915.         {
  916.           tree_fvc *defn = sym_rec->def ();
  917.  
  918.           assert (defn && defn->is_constant ());
  919.  
  920.           tree_constant *tmp = (tree_constant *) defn;
  921.  
  922.           int var_ok = 1;
  923.           if (tmp && tmp->is_map ())
  924.             {
  925.               if (! elts.empty ())
  926.             {
  927.               octave_value ult =
  928.                 tmp->lookup_map_element (elts, 0, 1);
  929.  
  930.               if (! ult.is_defined ())
  931.                 var_ok = 0;                
  932.             }
  933.             }
  934.  
  935.           if (nargout == 0 && ! quiet)
  936.             {
  937.               if (var_ok)
  938.             {
  939.               output_buf << argv[i];
  940.               if (sym_rec->is_user_variable ())
  941.                 output_buf << " is a user-defined variable\n";
  942.               else
  943.                 output_buf << " is a built-in variable\n";
  944.             }
  945.               else
  946.             {
  947.               if (! elts.empty ())
  948.                 output_buf << "type: structure `" << id
  949.                   << "' has no member `" << elts << "'\n";
  950.               else
  951.                 output_buf << "type: `" << id
  952.                   << "' has unknown type!\n";
  953.             }
  954.             }
  955.           if (! tmp->is_map ())
  956.             {
  957.               tree_print_code tpc (output_buf, "", pr_orig_txt);
  958.  
  959.               tmp->accept (tpc);
  960.  
  961.               if (nargout == 0)
  962.             output_buf << "\n";
  963.             }
  964.         }
  965.           else
  966.         output_buf << "type: `" << argv[i] << "' has unknown type!\n";
  967.         }
  968.       else
  969.         output_buf << "type: `" << argv[i] << "' undefined\n";
  970.     }
  971.  
  972.       output_buf << ends;
  973.  
  974.       char *s = output_buf.str ();
  975.  
  976.       if (nargout == 0)
  977.     octave_stdout << s;
  978.       else
  979.     retval = s;
  980.  
  981.       delete [] s;
  982.     }
  983.   else
  984.     print_usage ("type");
  985.  
  986.   return retval;
  987. }
  988.  
  989. DEFUN_TEXT (which, args, nargout,
  990.   "which NAME ...\n\
  991. \n\
  992. display the type of each NAME.  If NAME is defined from an function\n\
  993. file, print the full name of the file.")
  994. {
  995.   octave_value_list retval;
  996.  
  997.   int argc = args.length () + 1;
  998.  
  999.   string_vector argv = args.make_argv ("which");
  1000.  
  1001.   if (error_state)
  1002.     return retval;
  1003.  
  1004.   if (argc > 1)
  1005.     {
  1006.       if (nargout > 0)
  1007.     retval.resize (argc-1, Matrix ());
  1008.  
  1009.       for (int i = 1; i < argc; i++)
  1010.     {
  1011.       symbol_record *sym_rec = lookup_by_name (argv[i], 0);
  1012.  
  1013.       if (sym_rec)
  1014.         {
  1015.           int print = (nargout == 0);
  1016.           string tmp = print_symbol_type (octave_stdout, sym_rec,
  1017.                           argv[i], print);
  1018.           if (! print)
  1019.         retval(i) = tmp;
  1020.         }
  1021.       else
  1022.         {
  1023.           if (nargout == 0)
  1024.         octave_stdout << "which: `" << argv[i] << "' is undefined\n";
  1025.           else
  1026.         retval(i) = "undefined";
  1027.         }
  1028.     }
  1029.     }
  1030.   else
  1031.     print_usage ("which");
  1032.  
  1033.   return retval;
  1034. }
  1035.  
  1036. static int
  1037. suppress_verbose_help_message (void)
  1038. {
  1039.   Vsuppress_verbose_help_message
  1040.     = check_preference ("suppress_verbose_help_message");
  1041.  
  1042.   return 0;
  1043. }
  1044.  
  1045. static int
  1046. info_file (void)
  1047. {
  1048.   int status = 0;
  1049.  
  1050.   string s = builtin_string_variable ("INFO_FILE");
  1051.  
  1052.   if (s.empty ())
  1053.     {
  1054.       gripe_invalid_value_specified ("INFO_FILE");
  1055.       status = -1;
  1056.     }
  1057.   else
  1058.     Vinfo_file = s;
  1059.  
  1060.   return status;
  1061. }
  1062.  
  1063. static int
  1064. info_prog (void)
  1065. {
  1066.   int status = 0;
  1067.  
  1068.   string s = builtin_string_variable ("INFO_PROGRAM");
  1069.  
  1070. #ifndef __EMX__
  1071.   if (s.empty ())
  1072.     {
  1073.       gripe_invalid_value_specified ("INFO_PROGRAM");
  1074.       status = -1;
  1075.     }
  1076.   else
  1077.     Vinfo_prog = s;
  1078. #else
  1079.   Vinfo_prog = s;
  1080. #endif
  1081.  
  1082.   return status;
  1083. }
  1084.  
  1085. void
  1086. symbols_of_help (void)
  1087. {
  1088.   DEFVAR (INFO_FILE, Vinfo_file, 0, info_file,
  1089.     "name of the Octave info file");
  1090.  
  1091.   DEFVAR (INFO_PROGRAM, Vinfo_prog, 0, info_prog,
  1092.     "name of the Octave info reader");
  1093.  
  1094.   DEFVAR (suppress_verbose_help_message, 0.0, 0, suppress_verbose_help_message,
  1095.     "suppress printing of message pointing to additional help in the\n\
  1096. help and usage functions");
  1097. }
  1098.  
  1099. /*
  1100. ;;; Local Variables: ***
  1101. ;;; mode: C++ ***
  1102. ;;; End: ***
  1103. */
  1104.